package com.desay.pangoo.itmt.service.impl;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;

import cn.hutool.core.collection.CollUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.desay.pangoo.common.lite.lang.web.BusinessException;
import com.desay.pangoo.itmt.config.AICompletionProperties;
import com.desay.pangoo.itmt.dto.LlmCompletionDTO;
import com.desay.pangoo.itmt.dto.LlmCompletionRespDTO;
import com.desay.pangoo.itmt.dto.LlmInitDTO;
import com.desay.pangoo.itmt.dto.UpdateTechProjectDTO;
import com.desay.pangoo.itmt.entity.TechProjectInfoEntity;
import com.desay.pangoo.itmt.enums.ExceptionCodeEnum;
import com.desay.pangoo.itmt.service.LLMService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.log4j.Log4j2;
import okhttp3.*;

/**
 * 对接AI大模型的接口实现类
 *
 * @author uids1175
 */

@Log4j2
@Service
public class LLMServiceImpl implements LLMService {

	@Autowired
	private OkHttpClient okHttpClient;

	@Autowired
	private AICompletionProperties properties;

	@Autowired
	private ObjectMapper objectMapper;

	/**
	 * 初始化AI大模型
	 *
	 * @param dto
	 *            初始化需要的参数
	 */
	@Async("asyncAIMessageExecutor")
	@Override
	public void initLlm(LlmInitDTO dto) {
		// 构建请求Url
		String url = properties.getUri() + properties.getInitAiApi();

		// 构造请求参数
		LlmInitDTO initDTO = new LlmInitDTO();
		initDTO.setKeepAlive(-1);

		// 调用AI生成内容的接口
		Integer respStatus = 0;
		try {
			// 构建请求体
			RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse(MediaType.APPLICATION_JSON_VALUE),
					objectMapper.writeValueAsString(initDTO));
			// 构建初始化请求对象
			Request request = new Request.Builder().url(url).method(HttpMethod.POST.name(), requestBody).build();
			Response response = okHttpClient.newCall(request).execute();
			respStatus = response.code();
			response.close();
		} catch (Exception e) {
			log.error("发生异常: ", e);
			throw new BusinessException(ExceptionCodeEnum.RAG_CHAT_SERVICE_ERROR);
		}

		if (!respStatus.equals(200)) {
			log.error("itmt:rag desc:算法服务初始化失败");
		}
	}

	/**
	 * 调用AI大模型生成接口，接收大模型返回的流式数据
	 *
	 * @param dto
	 *            参数实体
	 * @return 返回的流式数据
	 */
	@Override
	public LlmCompletionRespDTO completion(LlmCompletionDTO dto) {
		// 构造 AI生成的接口url
		String url = properties.getUri() + properties.getCompletionApi();

		// 调用AI生成内容的接口
		LlmCompletionRespDTO respDTO = new LlmCompletionRespDTO();

		try {
			// 构建请求体
			RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse(MediaType.APPLICATION_JSON_VALUE),
					objectMapper.writeValueAsString(dto));

			// 构建请求对象
			Request request = new Request.Builder().url(url).method(HttpMethod.POST.name(), requestBody).build();

			Response response = okHttpClient.newCall(request).execute();
			if (response.code() != HttpStatus.OK.value()) {
				// 返回一个默认的应答
				String path = "defaultMessage.json";
				String defaultMessage = getDefaultMessage(path);
				respDTO.setInputStream(new ByteArrayInputStream(defaultMessage.getBytes(Charsets.UTF_8)));
				return respDTO;
			}
			String metadata = response.header("metadata");
			respDTO.setMetaData(metadata);
			ResponseBody responseBody = response.body();
			if (responseBody != null) {
				respDTO.setInputStream(responseBody.byteStream());
			}
		} catch (Exception e) {
			log.error("发生异常: ", e);
			// 保留原始异常信息
			throw new BusinessException(ExceptionCodeEnum.RAG_CHAT_SERVICE_ERROR);
		}

		return respDTO;
	}

	@Override
	public LlmCompletionRespDTO summary(LlmCompletionDTO dto) {
		// 构造 AI生成的接口url
		String url = properties.getUri() + properties.getSummaryApi();

		// 调用AI生成内容的接口
		LlmCompletionRespDTO respDTO = new LlmCompletionRespDTO();

		try {
			// 构建请求体
			RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse(MediaType.APPLICATION_JSON_VALUE),
					objectMapper.writeValueAsString(dto));

			// 构建请求对象
			Request request = new Request.Builder().url(url).method(HttpMethod.POST.name(), requestBody).build();

			Response response = okHttpClient.newCall(request).execute();
			if (response.code() != HttpStatus.OK.value()) {
				// 返回一个默认的应答
				String path = "defaultMessage.json";
				String defaultMessage = getDefaultMessage(path);
				respDTO.setInputStream(new ByteArrayInputStream(defaultMessage.getBytes(Charsets.UTF_8)));
				return respDTO;
			}
			String metadata = response.header("metadata");
			respDTO.setMetaData(metadata);
			if (response.body() != null) {
				respDTO.setInputStream(response.body().byteStream());
			}
		} catch (Exception e) {
			log.error("发生异常: ", e);
			if (e instanceof BusinessException) {
				throw (BusinessException) e;
			}
			throw new BusinessException(ExceptionCodeEnum.RAG_CHAT_SERVICE_ERROR);
		}

		return respDTO;
	}

	/**
	 * 发送TechProject信息给算法端
	 * 
	 * @param techProjectInfoEntityList
	 * @return
	 */
	@Override
	public Boolean sendTechProject(List<TechProjectInfoEntity> techProjectInfoEntityList) {
		if (CollUtil.isEmpty(techProjectInfoEntityList)) {
			return true;
		}
		// 构造请求体
		UpdateTechProjectDTO updateTechProjectDTO = new UpdateTechProjectDTO();
		updateTechProjectDTO.setProjectData(techProjectInfoEntityList);
		// 为null的不序列化
		// 创建ObjectMapper实例，用于JSON序列化和反序列化操作
		ObjectMapper objectMapper = new ObjectMapper();

		// 将包含循环引用的对象进行序列化
		String json = "";
		try {
			json = objectMapper.writeValueAsString(updateTechProjectDTO);
		} catch (Exception e) {
			log.error("发生异常: ", e);
			return false;
		}
		RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json"), json);
		// 构造请求
		Request.Builder requestBuilder = new Request.Builder();
		String url = properties.getUri() + properties.getUpdateTechProjectApi();
		Request request = requestBuilder.url(url).method("POST", requestBody).build();
		Call call = okHttpClient.newCall(request);

		// 发出HTTP请求
		try {
			Response response = call.execute();
			int code = response.code();
			response.close();
			return code == HttpStatus.OK.value();
		} catch (IOException e) {
			log.warn(e.getMessage());
			return false;
		}
	}

	/**
	 * 获取AI返回错误时，需要返回的默认回答
	 * 
	 * @return
	 */
	private String getDefaultMessage(String path) {
		ClassPathResource classPathResource = new ClassPathResource(path);
		BufferedReader reader = classPathResource.getReader(StandardCharsets.UTF_8);
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line).append("\n");
			}
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return sb.toString();
	}

	/**
	 * 查询树形结构相关数据
	 *
	 * @param data
	 *            请求数据
	 * @return 返回树形结构相关数据的JSON对象
	 * @throws BusinessException
	 *             当请求发生异常时抛出业务异常
	 */
	@Override
	public JSONObject treeRelated(JSONObject data) {
		RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json"),
				JSONUtil.toJsonStr(data));
		// post接口访问，返回数据结构
		Request.Builder requestBuilder = new Request.Builder();
		String url = properties.getUri() + properties.getTreeRelatedApi();
		Request request = requestBuilder.url(url).method("POST", requestBody).build();
		try (Response response = okHttpClient.newCall(request).execute()) {
			// 返回：
			// 状态200：
			// 不存在相关提案返回：{}
			if (response.isSuccessful()) {
				String body = response.body().string();
				log.info("treeRelated: {}", body);
				// 返回body 是一个map<key,value>
				return new JSONObject(body);
			} else {
				throw new BusinessException(ExceptionCodeEnum.RAG_CHAT_SERVICE_ERROR);
			}
		} catch (IOException e) {
			log.error(e.getMessage());
			throw new BusinessException(ExceptionCodeEnum.RAG_CHAT_SERVICE_ERROR);
		}
	}

	@Override
	public JSONObject projectChart(JSONObject data) {
		RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json"),
				JSONUtil.toJsonStr(data));
		// post接口访问，返回数据结构
		Request.Builder requestBuilder = new Request.Builder();
		String url = properties.getUri() + properties.getProjectChat();
		Request request = requestBuilder.url(url).method("POST", requestBody).build();
		try (Response response = okHttpClient.newCall(request).execute()) {
			// 返回：
			// 状态200：
			if (response.isSuccessful()) {
				String body = response.body().string();
				// 返回body 是一个map<key,value>
				return new JSONObject(body);
			} else {
				throw new BusinessException(ExceptionCodeEnum.RAG_CHAT_SERVICE_ERROR);
			}
		} catch (IOException e) {
			log.error(e.getMessage());
			throw new BusinessException(ExceptionCodeEnum.RAG_CHAT_SERVICE_ERROR);
		}
	}
}
